package com.getpebble.android.framework.endpoint;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import com.getpebble.android.bluetooth.protocol.ProtocolMessage;
import com.getpebble.android.common.core.trace.Trace;
import com.getpebble.android.common.core.util.ByteUtil;
import com.getpebble.android.common.model.FrameworkState;
import com.getpebble.android.framework.protocol.EndpointId;
import com.getpebble.android.framework.protocol.inbound.PblInboundLogDumpMessage;
import com.getpebble.android.framework.protocol.inbound.PblInboundLogDumpMessage.ResponseType;
import com.getpebble.android.framework.protocol.outbound.PblOutboundLogDumpMessage;
import com.getpebble.android.framework.util.ByteUtils;
import com.google.common.collect.ImmutableSet;
import com.sun.mail.imap.protocol.ListInfo;
import com.sun.mail.smtp.SMTPMessage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPOutputStream;

public class LogDumpEndpoint extends RequestableEndpoint {
    public static final String TAG = LogDumpEndpoint.class.getSimpleName();
    private final Context mContext;
    private File mFile;
    private StringBuilder mFormattedLogs;
    private FrameworkState mFrameworkState;
    private AtomicInteger mGenerationId;
    private final Handler mHandler;
    private int mLogCount;
    private final IEndpointMessageSender mMessageSender;
    private byte[] mPendingCookie;
    private State mState;
    private final Runnable mTimeoutRunnable = new Runnable() {
        public void run() {
            Trace.warning(LogDumpEndpoint.TAG, "Timeout!");
            synchronized (LogDumpEndpoint.this) {
                LogDumpEndpoint.this.finish();
            }
        }
    };

    static /* synthetic */ class AnonymousClass2 {
        static final /* synthetic */ int[] $SwitchMap$com$getpebble$android$framework$protocol$inbound$PblInboundLogDumpMessage$ResponseType = new int[ResponseType.values().length];

        static {
            try {
                $SwitchMap$com$getpebble$android$framework$protocol$inbound$PblInboundLogDumpMessage$ResponseType[ResponseType.DONE.ordinal()] = 1;
            } catch (NoSuchFieldError e) {
            }
            try {
                $SwitchMap$com$getpebble$android$framework$protocol$inbound$PblInboundLogDumpMessage$ResponseType[ResponseType.LOG.ordinal()] = 2;
            } catch (NoSuchFieldError e2) {
            }
            try {
                $SwitchMap$com$getpebble$android$framework$protocol$inbound$PblInboundLogDumpMessage$ResponseType[ResponseType.STATS_DUMP_DONE.ordinal()] = 3;
            } catch (NoSuchFieldError e3) {
            }
        }
    }

    public enum Result {
        SUCCESS(1),
        ERROR_UNKNOWN(0),
        ERROR_FILE_WRITE_FAILED(-1),
        ERROR_SEND_FAILURE(-2),
        ERROR_INVALID_MESSAGE(-3),
        ERROR_ALREADY_IN_PROGRESS(-4),
        ERROR_PRF(-5),
        ERROR_TIMEOUT(-6);
        
        private final int mValue;

        private Result(int value) {
            this.mValue = value;
        }

        public static Result fromValue(int value) {
            for (Result result : values()) {
                if (result.getValue() == value) {
                    return result;
                }
            }
            return ERROR_UNKNOWN;
        }

        public int getValue() {
            return this.mValue;
        }
    }

    private enum State {
        INIT,
        FETCHING
    }

    public LogDumpEndpoint(Context context, IEndpointMessageSender messageSender) throws IllegalArgumentException {
        if (context == null) {
            throw new IllegalArgumentException("'context' cannot be null!");
        } else if (messageSender == null) {
            throw new IllegalArgumentException("'messageSender' cannot be null!");
        } else {
            this.mContext = context;
            this.mMessageSender = messageSender;
            this.mHandler = new Handler(Looper.getMainLooper());
            this.mState = State.INIT;
        }
    }

    boolean onRequest(EndpointRequest request, FrameworkState frameworkState) {
        if (!isRequestSupported(request)) {
            return false;
        }
        this.mFrameworkState = frameworkState;
        startLogDump();
        return true;
    }

    boolean onPrfRequest(EndpointRequest request, FrameworkState frameworkState) {
        if (!isRequestSupported(request)) {
            return false;
        }
        this.mFrameworkState = frameworkState;
        sendResult(Result.ERROR_PRF);
        return true;
    }

    Set<EndpointId> getSupportedEndpoints() {
        return ImmutableSet.of(EndpointId.LOG_DUMP);
    }

    boolean onReceive(ProtocolMessage message) {
        synchronized (this) {
            if (message == null) {
                Trace.error(TAG, "Got null protocol message");
                sendResult(Result.ERROR_INVALID_MESSAGE);
                cleanup();
                return false;
            } else if (!getSupportedEndpoints().contains(EndpointId.fromCode(message.getEndpointId()))) {
                Trace.warning(TAG, "Unsupported endpoint: " + message.getEndpointId());
                return false;
            } else if (this.mPendingCookie == null) {
                Trace.error(TAG, "Received log dump message but no cookie was set");
                cleanup();
                return true;
            } else {
                try {
                    PblInboundLogDumpMessage logMessage = new PblInboundLogDumpMessage(message);
                    if (Arrays.equals(this.mPendingCookie, logMessage.getCookie())) {
                        switch (AnonymousClass2.$SwitchMap$com$getpebble$android$framework$protocol$inbound$PblInboundLogDumpMessage$ResponseType[logMessage.getResponseType().ordinal()]) {
                            case SMTPMessage.RETURN_FULL /*1*/:
                                Trace.debug(TAG, "Completed generation, cancelling timeout");
                                cancelTimeout();
                                boolean fetchNextGen = fetchNextGen();
                                return fetchNextGen;
                            case SMTPMessage.RETURN_HDRS /*2*/:
                                this.mFormattedLogs.append(logMessage.getLog().getFormattedMessage()).append("\n");
                                sendPingIfRequired();
                                cancelTimeout();
                                startTimeout();
                                return true;
                            case ListInfo.INDETERMINATE /*3*/:
                                Trace.warning(TAG, "Ignoring 'stats dump done' message");
                                return true;
                            default:
                                Trace.error(TAG, "Received unknown response type: " + logMessage.getResponseType());
                                sendResult(Result.ERROR_INVALID_MESSAGE);
                                cleanup();
                                return true;
                        }
                    }
                    Trace.error(TAG, String.format("Expected cookie <%s> got <%s>; dropping message", new Object[]{ByteUtil.byteArrayToHexString(this.mPendingCookie, this.mPendingCookie.length), ByteUtil.byteArrayToHexString(logMessage.getCookie(), logMessage.getCookie().length)}));
                    sendResult(Result.ERROR_INVALID_MESSAGE);
                    cleanup();
                    return true;
                } catch (IllegalArgumentException e) {
                    Trace.warning(TAG, "Failed to handle log message", e);
                    sendResult(Result.ERROR_INVALID_MESSAGE);
                    cleanup();
                    return true;
                }
            }
        }
    }

    public boolean startLogDump() {
        boolean z = false;
        if (this.mState != State.INIT) {
            Trace.warning(TAG, "Log dump busy; current state: " + this.mState);
            sendResult(Result.ERROR_ALREADY_IN_PROGRESS);
        } else {
            Trace.verbose(TAG, "Starting log dump..");
            synchronized (this) {
                this.mState = State.FETCHING;
                this.mLogCount = 0;
                File oldLogDump = getFile();
                if (oldLogDump.exists()) {
                    if (oldLogDump.delete()) {
                        Trace.debug(TAG, "Removed old log dump file");
                    } else {
                        Trace.error(TAG, "Old log dump file exists, but could not be removed");
                    }
                }
                this.mFile = null;
                this.mFormattedLogs = new StringBuilder();
                this.mGenerationId = new AtomicInteger(0);
                z = fetchNextGen();
            }
        }
        return z;
    }

    private File getFile() {
        if (this.mFile == null) {
            this.mFile = new File(getContext().getExternalCacheDir(), "device-logs.log.gz");
        }
        return this.mFile;
    }

    private Context getContext() {
        return this.mContext;
    }

    private IEndpointMessageSender getMessageSender() {
        return this.mMessageSender;
    }

    private void cleanup() {
        Trace.debug(TAG, "Cleaning up");
        cancelTimeout();
        this.mFrameworkState = null;
        this.mGenerationId = null;
        this.mPendingCookie = null;
        this.mFormattedLogs = null;
        synchronized (this) {
            this.mState = State.INIT;
        }
    }

    private void startTimeout() {
        this.mHandler.postDelayed(this.mTimeoutRunnable, 3000);
    }

    private void cancelTimeout() {
        this.mHandler.removeCallbacks(this.mTimeoutRunnable);
    }

    private void sendResult(Result result) {
        Trace.debug(TAG, "Sending result: " + result);
        String filename = null;
        if (this.mFile != null) {
            filename = this.mFile.getAbsolutePath();
        }
        this.mFrameworkState.setLogDumpResult(result.getValue(), filename);
    }

    private void sendPingIfRequired() {
        int i = this.mLogCount;
        this.mLogCount = i + 1;
        if (i % 250 == 0) {
            this.mFrameworkState.sendLogCoreDumpPing();
        }
    }

    private void finish() {
        Exception e;
        Throwable th;
        Trace.debug(TAG, "Writing logs to file; count = " + this.mLogCount);
        PrintStream printStream = null;
        boolean isError = false;
        try {
            PrintStream printStream2 = new PrintStream(new GZIPOutputStream(new FileOutputStream(getFile(), true)));
            try {
                printStream2.println("# Device logs:");
                printStream2.print(this.mFormattedLogs.toString());
                if (printStream2 != null) {
                    printStream2.flush();
                    printStream2.close();
                    printStream = printStream2;
                } else {
                    printStream = printStream2;
                }
            } catch (Exception e2) {
                e = e2;
                printStream = printStream2;
                try {
                    Trace.error(TAG, "Uncaught exception writing logs to file", e);
                    isError = true;
                    if (printStream != null) {
                        printStream.flush();
                        printStream.close();
                    }
                    if (!isError) {
                    }
                    sendResult(Result.ERROR_FILE_WRITE_FAILED);
                    cleanup();
                } catch (Throwable th2) {
                    th = th2;
                    if (printStream != null) {
                        printStream.flush();
                        printStream.close();
                    }
                    throw th;
                }
            } catch (Throwable th3) {
                th = th3;
                printStream = printStream2;
                if (printStream != null) {
                    printStream.flush();
                    printStream.close();
                }
                throw th;
            }
        } catch (Exception e3) {
            e = e3;
            Trace.error(TAG, "Uncaught exception writing logs to file", e);
            isError = true;
            if (printStream != null) {
                printStream.flush();
                printStream.close();
            }
            if (isError) {
            }
            sendResult(Result.ERROR_FILE_WRITE_FAILED);
            cleanup();
        }
        if (isError || printStream.checkError()) {
            sendResult(Result.ERROR_FILE_WRITE_FAILED);
        } else {
            sendResult(Result.SUCCESS);
        }
        cleanup();
    }

    private boolean fetchNextGen() {
        if (this.mState != State.FETCHING) {
            Trace.error(TAG, "Not properly initialized");
            sendResult(Result.ERROR_ALREADY_IN_PROGRESS);
            cleanup();
            return false;
        } else if (this.mGenerationId.get() == 4) {
            Trace.debug(TAG, "Done fetching logs");
            finish();
            return false;
        } else {
            byte generationId = this.mGenerationId.byteValue();
            this.mFormattedLogs.append("=== Generation: ").append(this.mGenerationId.get()).append(" ===").append("\n");
            this.mGenerationId.incrementAndGet();
            byte[] cookie = ByteUtils.randomCookie();
            if (getMessageSender().sendMessage(new PblOutboundLogDumpMessage(generationId, cookie))) {
                Trace.debug(TAG, "Log dump sent successfully for generation: " + generationId);
                startTimeout();
                this.mPendingCookie = cookie;
                return true;
            }
            Trace.error(TAG, "Failed to send log dump for generation: " + generationId);
            sendResult(Result.ERROR_SEND_FAILURE);
            cleanup();
            return false;
        }
    }
}
